using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.DirectX;
using Microsoft.DirectX.DirectInput;
using System.Threading;

namespace JoyStickController
{
    public class Joystick
    {

        static Joystick(){
			DeviceList dl = Manager.GetDevices(DeviceType.Joystick, EnumDevicesFlags.AttachedOnly);
        }

		private Device joystick = null;

		/// <summary>
		/// Joystickmanager constructor
        /// Using http://www.idi.ntnu.no/~fredrior/files/Joystick.NET/Joystick.cs
		/// </summary>
		public Joystick () {
			// enumerate all devices
			DeviceList dl = Manager.GetDevices(DeviceType.Joystick, EnumDevicesFlags.AttachedOnly);
			
			while ( dl.MoveNext() ) {
				DeviceInstance di = (DeviceInstance)dl.Current;
				
				if ( di.DeviceType == DeviceType.Joystick ) {
					// we've found a joystick :)
					joystick = new Device( di.ProductGuid );
					joystick.Acquire();

					//new Thread(new ThreadStart(DebugFunction) ).Start();
					return;
				}
			}
			throw new Exception("ERROR: joystick not found.");
		}

		
		/// <summary>
		/// Current joystick state with axes in range [-1, 1].
		/// positive X right, positive Y up and positive ROT clockwise
		/// </summary>
		public JoyState State { get {
				JoystickState state = joystick.CurrentJoystickState;
				return new JoyState(state);
			}
		}

		public void DebugFunction () {
			Thread.CurrentThread.IsBackground = true;

			while (true) {
				JoyState state = State;
				Console.WriteLine(state);
				Thread.Sleep(500);
			}
		}

	}

	/// <summary>
	/// Easy to use Joystick-state structure
	/// Tailored for the Logitech Freedom 2.4 joystick with 4 axes, 10 buttons and a "hat"
	/// </summary>
    public struct JoyState
    {
        // analog axis in range [-1,+1]
        public float X, Y, R, S;
        // buttons
        public bool B1, B2, B3, B4, B5, B6, B7, B8;
        // joystick hat axes in range {-1, 0, +1}
        public int HAT_X, HAT_Y;

        public JoyState(JoystickState state)
        {
            const float center = 32768.0f - 0.5f;

            // axes in range [-1,+1]
            X = (state.X - center) / center; // positive right
            Y = -(state.Y - center) / center; // positive up
            R = (state.Rz - center) / center; // positive clockwise
            S = -(state.Z - center) / center; // positive up
            // clamp small values to zero
            if (Math.Abs(X) < 0.09) X = 0;
            if (Math.Abs(Y) < 0.09) Y = 0;
            if (Math.Abs(R) < 0.09) R = 0;
            if (Math.Abs(S) < 0.09) S = 0;

            // buttons
            byte[] buttons = state.GetButtons();
            B1 = buttons[0] >= 128;
            B2 = buttons[1] >= 128;
            B3 = buttons[2] >= 128;
            B4 = buttons[3] >= 128;
            B5 = buttons[4] >= 128;
            B6 = buttons[5] >= 128;
            B7 = buttons[6] >= 128;
            B8 = buttons[7] >= 128;
            //B9 = buttons[8] >= 128;
            //B10 = buttons[9] >= 128;

            // joystick hat state
            int hat = state.GetPointOfView()[0];
            HAT_X = 0; HAT_Y = 0;
            if (hat != -1)
            {
                int h = hat / 1000;
                if (h > 0 && h < 18) HAT_X = 1;
                if (h > 18 && h < 36) HAT_X = -1;
                if (h > 9 && h < 27) HAT_Y = -1;
                if (h > 27 || h < 9) HAT_Y = 1;
            }
        }

        // intuitive string representation
        public override string ToString()
        {
            string s = "X: " + X + ", Y: " + Y + ", R: " + R + ", S: " + S + "\n";
            s = s + "B1: " + B1 + ", B2: " + B2 + ", B3: " + B3 + ", B4: " + B4 + ", B5: " + B5 + ", B6: " + B6 + ", B7: " + B7 + ", B8: " + B8 + "\n";
            s = s + "HAT_X: " + HAT_X + ", HAT_Y: " + HAT_Y + "\n";
            return s;
        }

    }
}
